package com.r2coding.domain.strategy.service.armory.impl;

import com.r2coding.domain.strategy.model.entity.StrategyAwardEntity;
import com.r2coding.domain.strategy.model.entity.StrategyEntity;
import com.r2coding.domain.strategy.model.entity.StrategyRuleEntity;
import com.r2coding.domain.strategy.model.res.StrategyAwardRateSearchTableRes;
import com.r2coding.domain.strategy.repository.IStrategyRepository;
import com.r2coding.domain.strategy.service.armory.IStrategyArmory;
import com.r2coding.domain.strategy.service.armory.IStrategyDispatch;
import com.r2coding.types.enums.ResponseCode;
import com.r2coding.types.exception.AppException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 抽奖概率装配库Service实现类
 *
 * @author caolx
 * @date 2025/7/25 7:24
 */
@Service
public class StrategyArmoryDispatch implements IStrategyArmory, IStrategyDispatch {

    @Resource
    private IStrategyRepository strategyRepository;

    @Override
    public boolean assembleLotteryStrategy(Long strategyId) {
        // 1、查询抽奖策略下配置的奖品
        List<StrategyAwardEntity> strategyAwardEntityList = strategyRepository.queryStrategyAwardList(strategyId);
        if (strategyAwardEntityList.isEmpty()) {
            return false;
        }

        // 2、装配抽奖策略奖品概率查找表
        this.assembleStrategyRateTable(strategyId, strategyAwardEntityList);

        StrategyEntity strategyEntity = strategyRepository.queryStrategyEntity(strategyId);
        String ruleWeightModel = strategyEntity.getRuleWeightModel();
        if (ruleWeightModel == null) {
            return true;
        }

        // 3、查询策略权重规则配置
        StrategyRuleEntity strategyRuleEntity = strategyRepository.queryStrategyRuleEntity(strategyId, ruleWeightModel);
        if (strategyRuleEntity == null) {
            throw new AppException(ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getCode(), ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getInfo());
        }
        // 4000:102,103,104,105;5000:102,103,104,105,106,107;6000:102,103,104,105,106,107,108,109
        Map<Integer, List<Integer>> ruleWeightValueMap = strategyRuleEntity.getRuleWeightValues();
        for (Map.Entry<Integer, List<Integer>> ruleWeightValueEntry : ruleWeightValueMap.entrySet()) {
            Integer ruleWeightValue = ruleWeightValueEntry.getKey();
            List<Integer> ruleWeightValueList = ruleWeightValueEntry.getValue();
            List<StrategyAwardEntity> ruleWeightStrategyAwardEntityList = strategyAwardEntityList.stream()
                    .filter(strategyAwardEntity -> ruleWeightValueList.contains(strategyAwardEntity.getAwardId()))
                    .collect(Collectors.toList());
            // 装配抽奖策略奖品概率查找表
            this.assembleStrategyWeightRateTable(strategyId, ruleWeightValue, ruleWeightStrategyAwardEntityList);
        }
        return true;
    }

    @Override
    public Integer getRandomAwardId(Long strategyId) {
        // 获取策略ID对应的奖品中奖概率范围
        Integer rateRange = strategyRepository.getRateRange(strategyId);
        return strategyRepository.getStrategyAwardAssemble(strategyId, new SecureRandom().nextInt(rateRange));
    }

    @Override
    public Integer getRuleWeightRandomAwardId(Long strategyId, Integer ruleWeight) {
        // 获取策略ID对应的奖品中奖概率范围
        Integer rateRange = strategyRepository.getRuleWeightRateRange(strategyId, ruleWeight);
        return strategyRepository.getStrategyWeightAwardAssemble(strategyId, ruleWeight, new SecureRandom().nextInt(rateRange));
    }

    /**
     * 装配抽奖策略奖品概率查找表
     *
     * @param strategyId              策略ID
     * @param strategyAwardEntityList 抽奖策略奖品列表
     */
    private void assembleStrategyRateTable(Long strategyId, List<StrategyAwardEntity> strategyAwardEntityList) {
        // 1、生成抽奖策略奖品概率查找表
        StrategyAwardRateSearchTableRes searchTableRes = this.generateStrategyAwardRateSearchTable(strategyAwardEntityList);

        // 2、缓存至Redis
        strategyRepository.storeStrategyAwardSearchRateTable(strategyId, searchTableRes.getRateRange(), searchTableRes.getShuffledStrategyAwardSearchRateTable());
    }

    /**
     * 装配 抽奖策略权重奖品概率查找表
     *
     * @param strategyId              策略ID
     * @param ruleWeight              权重值
     * @param strategyAwardEntityList 抽奖策略奖品列表
     */
    private void assembleStrategyWeightRateTable(Long strategyId, Integer ruleWeight, List<StrategyAwardEntity> strategyAwardEntityList) {
        // 1、生成抽奖策略奖品概率查找表
        StrategyAwardRateSearchTableRes searchTableRes = generateStrategyAwardRateSearchTable(strategyAwardEntityList);

        // 2、缓存至Redis
        strategyRepository.storeStrategyWeightAwardSearchRateTable(strategyId, ruleWeight, searchTableRes.getRateRange(), searchTableRes.getShuffledStrategyAwardSearchRateTable());
    }

    /**
     * 根据奖品列表生成奖品概率查找表
     *
     * @param strategyAwardEntityList 奖品列表
     * @return 奖品概率查找表
     */
    private StrategyAwardRateSearchTableRes generateStrategyAwardRateSearchTable(List<StrategyAwardEntity> strategyAwardEntityList) {
        // 1、获取奖品概率最大小数位数（例如0.0001 -> 4，小数点后4位）
        int scale = strategyAwardEntityList.stream()
                .map(a -> a.getAwardRate().stripTrailingZeros().scale())
                .max(Integer::compareTo)
                .orElse(0);
        BigDecimal multiplier = BigDecimal.valueOf(Math.pow(10, scale));

        // 2、获取概率总和、概率范围
        BigDecimal totalAwardRate = strategyAwardEntityList.stream().map(StrategyAwardEntity::getAwardRate).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        BigDecimal rateRange = totalAwardRate.compareTo(BigDecimal.ONE) > 0 ? totalAwardRate.multiply(multiplier) : multiplier;

        // 3、生成策略奖品概率查找表
        List<Integer> strategyAwardSearchRateTables = new ArrayList<>();
        for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntityList) {
            Integer awardId = strategyAwardEntity.getAwardId();
            BigDecimal awardRate = strategyAwardEntity.getAwardRate();
            for (int i = 0; i < awardRate.multiply(multiplier).intValue(); i++) {
                strategyAwardSearchRateTables.add(awardId);
            }
        }

        // 4、随机打乱查找表
        Collections.shuffle(strategyAwardSearchRateTables);

        // 5、生成Map集合，key值对应概率值。通过概率获得对应的奖品ID
        Map<Integer, Integer> shuffledStrategyAwardSearchRateTable = new HashMap<>();
        for (int i = 0; i < strategyAwardSearchRateTables.size(); i++) {
            shuffledStrategyAwardSearchRateTable.put(i, strategyAwardSearchRateTables.get(i));
        }

        // 6、返回结果
        return StrategyAwardRateSearchTableRes.builder()
                .rateRange(rateRange)
                .shuffledStrategyAwardSearchRateTable(shuffledStrategyAwardSearchRateTable)
                .build();
    }
}
